#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <sstream>
#include <fstream>

#include <strings.h>

static const std::string sep = "\r\n";
static const std::string head_sep = ": ";

static const std::string wwwroot = "wwwroot";
static const std::string homepage = "index.html";

static const std::string httpversion = "HTTP/1.1";
static const std::string space = " ";

static const std::string filesuffix_sep = ".";

static const std::string get_sep = "?";

class HttpRequest
{
private:
    std::string GetOneLine(std::string &req)
    {
        if (req.empty())
            return std::string();
        auto pos = req.find(sep);
        if (pos == std::string::npos)
            return std::string();

        std::string line = req.substr(0, pos);
        req.erase(0, pos + sep.size());

        return line.empty() ? sep : line;
    }
    bool ParseHeadHelper(std::string &line, std::string *k, std::string *v)
    {
        if (line.empty())
            return false;
        auto pos = line.find(head_sep);
        *k = line.substr(0, pos);
        *v = line.substr(pos + head_sep.size());
        return true;
    }

public:
    HttpRequest() {}
    ~HttpRequest() {}

    // 反序列化
    void Derialize(std::string &req)
    {
        _req_line = GetOneLine(req);
        while (1)
        {
            std::string line = GetOneLine(req);
            if (line.empty())
                break;
            else if (line == sep)
            {
                _req_text = req;
                break;
            }
            else
            {
                _req_head.emplace_back(line);
            }
        }

        ParseReqLine();
        ParseHead();
    }

    void Print()
    {
        std::cout << "-------------------" << std::endl;
        std::cout << "***" << _req_line << "\r\n";
        for (auto &e : _req_head)
        {
            std::cout << "***" << e << "\r\n";
        }
        std::cout << "***" << _blank_line << "\r\n";
        std::cout << "***" << _req_text << "\r\n";

        std::cout << "###method  :" << _method << std::endl;
        std::cout << "###url  :" << _url << std::endl;
        std::cout << "###path  :" << _path << std::endl;
        std::cout << "###version  :" << _version << std::endl;

        for (auto &e : _heads)
        {
            std::cout << "###" << e.first << "  :" << e.second << std::endl;
        }
    }

    // 剖析请求行
    bool ParseReqLine()
    {
        if (_req_line.empty())
            return false;
        std::stringstream ss(_req_line);

        ss >> _method >> _url >> _version;
        // http服务会把接收到的请求做拼接
        _path += _url;
        if (_path[_path.size() - 1] == '/')
        {
            _path += homepage;
        }

        //请求方法
        if(strcasecmp(_method.c_str(),"get") == 0)
        {
            auto pos = _url.find(get_sep);
            if(pos != std::string::npos)
            {
                LOG(INFO,"change before:    %s",_url);
                _args = _url.substr(pos+get_sep.size());
                _url.resize(pos);
                LOG(INFO,"change after:     url: %s     args: %s",_url,_args);
            }
        }

        // 文件后缀名
        auto pos = _path.rfind(filesuffix_sep);
        if (pos == std::string::npos)
        {
            _suffix = ".html";
        }
        else
        {
            _suffix = _path.substr(pos);
        }
        LOG(INFO, "client want %s,the suffix:%s", _path.c_str(), _suffix.c_str());
        return true;
    }

    // 剖析请求头
    bool ParseHead()
    {
        for (auto &e : _req_head)
        {
            std::string k, v;
            if (ParseHeadHelper(e, &k, &v))
            {
                _heads.insert(std::make_pair(k, v));
            }
        }
        return true;
    }
    std::string Path()
    {
        return _path;
    }
    std::string Suffix()
    {
        return _suffix;
    }

private:
    std::string _req_line;              // 请求行
    std::vector<std::string> _req_head; // 请求头
    std::string _blank_line = "\r\n";   // 空行
    std::string _req_text;              // 请求内容

    // 进一步获取request中的信息
    std::string _method;
    std::string _url;
    std::string _path = wwwroot;
    std::string _version;
    std::unordered_map<std::string, std::string> _heads;

    std::string _suffix;

    std::string _args;//get方法中的请求参数
};

class HttpResponse
{
public:
    HttpResponse() {}
    ~HttpResponse() {}
    void AddStatLine(int code, std::string desc)
    {
        _code = code;
        _desc = desc;
    }
    void AddHead(const std::string k, const std::string v)
    {
        LOG(INFO, "%s:%s", k.c_str(), v.c_str());
        _heads[k] = v;
    }
    void AddText(std::string &text)
    {
        _resp_text = text;
    }

    std::string Serialize()
    {
        _stat_line = _version + space + std::to_string(_code) + space + _desc + sep;
        for (auto &e : _heads)
        {
            _resp_head.emplace_back(e.first + head_sep + e.second + sep);
        }

        // 开始序列化
        std::string resp_string;
        resp_string += _stat_line;
        for (auto &e : _resp_head)
        {
            resp_string += e;
        }
        resp_string += _blank_line;
        resp_string += _resp_text;

        return resp_string;
    }

private:
    std::string _stat_line;              // 状态行
    std::vector<std::string> _resp_head; // 响应头
    std::string _blank_line = "";        // 空行
    std::string _resp_text;              // 响应内容

    // 详细剖析
    std::string _version = httpversion; // 版本
    int _code;
    std::string _desc; // 状态码描述
    std::unordered_map<std::string, std::string> _heads;
};

class Factor
{
public:
    static std::shared_ptr<HttpRequest> BuildHttpRequest()
    {
        return std::make_shared<HttpRequest>();
    }
    static std::shared_ptr<HttpResponse> BuildHttpResponse()
    {
        return std::make_shared<HttpResponse>();
    }
};

class HttpServer
{
public:
    HttpServer()
    {

        _mime_type.insert(std::make_pair(".html", "text/html"));
        _mime_type.insert(std::make_pair(".css", "text/css"));
        _mime_type.insert(std::make_pair(".png", "image/png"));

        _code_to_desc.insert(std::make_pair(100, "Continue"));
        _code_to_desc.insert(std::make_pair(200, "OK"));
        _code_to_desc.insert(std::make_pair(301, "Moved Permanently"));
        _code_to_desc.insert(std::make_pair(400, "Bad Request"));
        _code_to_desc.insert(std::make_pair(404, "Not Found"));
    }
    // request大概率是一个完整的请求
    std::string ReadFileContent(const std::string &path, int *size)
    {
        std::ifstream in(path, std::ios::binary);
        if (!in.is_open())
        {
            return std::string();
        }

        in.seekg(0, in.end);
        int filesize = in.tellg();
        in.seekg(0, in.beg);

        std::string content;
        content.resize(filesize);
        in.read((char *)content.c_str(), filesize);
        in.close();

        *size = filesize;
        return content;
    }
    std::string HandlerHttpRequest(std::string request)
    {
#ifdef TEST
        std::cout << "---------" << std::endl;
        std::cout << request;
        // 简单的response
        std::string response = "HTTP/1.1 200 OK\r\n";
        response += "\r\n";
        response += "<html><body><h1>11111hhhh</h1></body></html>";
        return response;
#else
        // HttpRequest req;//开始序列化
        auto req = Factor::BuildHttpRequest();
        // 将一个字符串结构化，称为反序列化
        //  req->Derialize(request);
        //  req->ParseReqLine();
        //  req->ParseHead();
        //  req->Print();
        //  std::string response = "HTTP/1.1 200 OK\r\n";
        //  response+="\r\n";
        //  response+="<html><body>这是手写HTTP</body></html>";

        req->Derialize(request);
        // 构建响应
        auto resp = Factor::BuildHttpResponse();
        int code;
        //
        std::string newurl = "http://www.bilibili.com";
        if (req->Path() == "wwwroot/redir")
        {
            code = 301;
            resp->AddStatLine(code, _code_to_desc[code]);
            resp->AddHead("Location", newurl);
            std::string type = req->Suffix();
            resp->AddHead("Content-Type", _mime_type[type]);
        }
        else if(req->Path() == "wwwroot/login")
        {

        }
        else
        {
            std::string resource = req->Path();
            // 正文长度
            int contentlength = 0;
            // 文件内容
            std::string text = ReadFileContent(resource, &contentlength);
            if(text.empty())
            {
                code = 404;
                resp->AddStatLine(code, _code_to_desc[code]);
                std::string text404 = ReadFileContent("wwwroot/404.html", &contentlength);
                resp->AddHead("Content-Length",std::to_string(contentlength));
                resp->AddText(text404);
                std::string type = req->Suffix();
                resp->AddHead("Content-Type", "text/html");
            }
            else
            {
                code = 200;
                resp->AddStatLine(code, _code_to_desc[code]);
                resp->AddHead("Content-Length",std::to_string(contentlength));
                resp->AddText(text);
                std::string type = req->Suffix();
                resp->AddHead("Content-Type", _mime_type[type]);
            }
            
        }
        return resp->Serialize();
#endif
    }

    ~HttpServer() {}

private:
    std::unordered_map<std::string, std::string> _mime_type;
    std::unordered_map<int, std::string> _code_to_desc;
};